﻿using DataStandard.Tools;
using EasyModbus;
using JieKou.Modbus;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Authentication;
using System.Text;
using System.Threading;
using static JieKou.Modbus.WriteData;

namespace DataStandard.ProtocoType
{
    public class ModbusQi : InterfaceProtocoType
    {

        private ModbusClient Modbus = null;
        public int FunctionCode {  get; set; } 
        public bool IsRun => GetStatus();

        /// <summary>
        /// 是否自动重连
        /// </summary>
        public bool IsAutoReRun { get; set; } = false;

        private bool GetStatus()
        {
            if (Modbus == null)
            {
                throw new ArgumentException("Modbus = null 尚未进行初始化");
            }
            else
            {
                return Modbus.Connected;
            }
        }

        //我想用这个委托，把在本页面获取的数据返回到外面去。
        public delegate void ReBackDatas(object data);
        public event InterfaceProtocoType.ReBackDatas ReBackData;

        #region 待读写的数据队列

        /// <summary>
        /// 读取数据队列
        /// </summary>
        public Queue<DataItem> readDataSettings = new Queue<DataItem>();
        /// <summary>
        /// 写入数值队列
        /// </summary>
        public Queue<WriteDataValue> writeDataValues = new Queue<WriteDataValue>();
        /// <summary>
        /// 写入 1/0 队列
        /// </summary>
        public Queue<WriteDataBool> writeDataBools = new Queue<WriteDataBool>();


        #endregion


        #region 线程管理
        /// <summary>
        /// 线程计时器
        /// 在其他地方赋值
        /// </summary>
        private long millisecond_Thread = 0;
        /// <summary>
        /// 高配通信周期 毫秒
        /// </summary>
        private int t_Interval_Fine = 2;//高配通信周期 毫秒
        /// <summary>
        /// 重连通信周期 毫秒
        /// </summary>
        private int t_Interval_ReConnect = 100;//重连通信周期 毫秒
        /// <summary>
        /// 通信线程
        /// </summary>
        Thread thread = null;
        #endregion

        public ModbusQi()
        {
            OmegaTongXuntime();
        }

        

        public ModbusQi(ParameterTCP parameter) : this()
        {
            if (Modbus == null)
            {
                Modbus = new ModbusClient();
                Modbus.IPAddress = parameter.RemoteIP;
                Modbus.Port = parameter.RemotePort;
                Modbus.UnitIdentifier = parameter.RemoteID;

                FunctionCode = parameter.Functioncode;
            }
        }

        public ModbusQi(ParameterRTU parameter) : this()
        {
            if (Modbus == null)
            {
                Modbus = new ModbusClient();
                Modbus.SerialPort = parameter.SerialPortName;
                Modbus.Baudrate = parameter.BaudRate;
                Modbus.Parity = JieKou.Tools.IOPortParity.MakeChangeParityString(parameter.Parity);
                Modbus.StopBits = JieKou.Tools.IOPortParity.MakeChangeStopBitsString(parameter.StopBits);
                Modbus.UnitIdentifier = parameter.RemoteID;
            }
        }


        int RunCount = 0;
        public void Run()
        {
            if (RunCount == 0)
            {
                
                if (!IsRun)
                {
                    try
                    {
                        RunCount++;
                        Debug.WriteLine($"【{Thread.CurrentThread.ManagedThreadId.ToString()}】>>>>>>>>>>>>>>>>>>{RunCount}");
                        Modbus.Connect();
                    }
                    catch (Exception ex)
                    {
                        throw new Exception($"Modbus启动失败：{ex.Message}");
                    }
                    finally
                    {
                        RunCount = 0;
                        Debug.WriteLine($"【{Thread.CurrentThread.ManagedThreadId.ToString()}】>>>>>>>>>>>>>>>>>>{RunCount}");
                    }
                }
                else
                {
                    RunCount = 0;
                }
            }
            
        }

        public void Stop()
        {
            if (IsRun)
            {
                Modbus.Disconnect();
            }
        }
        /// <summary>
        /// 推送数据到队列中来。
        /// </summary>
        /// <param name="data"></param>
        public void PushReadData(object data)
        {
            if (data is DataItem)
            {
                var item = (DataItem)data;

                //先看看有没有好伙伴在给我们的任务排队？咱们来的目的就是为了获取数据嘛，有人在干我想干的事情，我就不干了。
                bool canFind = false;

                if (readDataSettings.Count > 0)
                {
                    foreach (var testItem in readDataSettings)
                    {
                        if (testItem.ParentName == item.ParentName &&
                            testItem.Description.StartAddress == item.Description.StartAddress &&
                            testItem.Description.Type == item.Description.Type &&
                            testItem.Description.BitIndex == item.Description.BitIndex &&
                            testItem.Description.UnitIdentifier == item.Description.UnitIdentifier &&
                            testItem.Description.Multiple == item.Description.Multiple &&
                            testItem.Description.Offset == item.Description.Offset &&
                            testItem.Description.RegisterOrder == item.Description.RegisterOrder &&
                            testItem.Description.SettingTimer == item.Description.SettingTimer)
                        {
                            //找到自己同伙了，咱们就不用排队了吧？让他继续站队，我们回去吧。
                            canFind = true;
                            break;
                        }
                    }
                }
                

                if (!canFind)
                {
                    //没有好伙伴在排队，那咱们自己排个号。
                    readDataSettings.Enqueue(item);
                }
                else
                {
                    //找到自己同伙了，咱们就不用排队了吧？让他继续站队，我们回去吧。无需处理。
                }
            }
            else
            {
                //无效数据，不用管。
            }
        }



        #region 线程部分
        /// <summary>
        /// 开线程
        /// </summary>
        private void OmegaTongXuntime()
        {
            thread = new Thread(new ThreadStart(OmegaTongXunThread));
            thread.IsBackground = true;//后台执行线程
            thread.Start();//开始线程
        }
        /// <summary>
        /// 线程内容
        /// </summary>
        private void OmegaTongXunThread()
        {
            millisecond_Thread = t_Interval_Fine;//倒计一分钟
            while (millisecond_Thread >= 0)
            {
                millisecond_Thread--;
                if (millisecond_Thread == 0)
                {
                    millisecond_Thread--;
                    //计时完成后推出应用程序

                    var testResult = JiShiQiWork();
                    if (testResult == "正常")
                    {
                        millisecond_Thread = t_Interval_Fine;
                    }
                    else if (testResult == "重连")
                    {
                        #region 重连机制
                        if (IsAutoReRun)
                        {
                            try
                            {
                                Run();
                                millisecond_Thread = t_Interval_ReConnect;
                            }
                            catch (Exception ex)
                            {
                                millisecond_Thread = t_Interval_ReConnect;
                            }


                        }
                        else
                        {
                            //不自动重连。
                            millisecond_Thread = t_Interval_Fine;

                        }
                        #endregion
                    }
                    else
                    {
                        millisecond_Thread = t_Interval_ReConnect;
                    }
                }
                Thread.Sleep(1);
            }

        }
        string JiShiQiWork()
        {
            string result = "正常";
            if (IsRun) 
            {
                if (readDataSettings.Count == 0)
                {
                    return result;//队列里面没有数据，但逻辑是正常的。
                }

                var temp = readDataSettings.Dequeue();

                try
                {
                    #region 正式读取数据

                    int[] temp_In_tempData = null;
                    switch (temp.Functioncode)
                    {
                        case 1:
                            {
                                var lastLength = temp.Description.ByteLength;
                                var startAddress = temp.Description.StartAddress;
                                Modbus.UnitIdentifier = temp.Description.UnitIdentifier;

                                var tempValueS = Modbus.ReadCoils(startAddress, 1);//线圈就读一个


                                temp.Description.NewReceivedBytes = BitConverter.GetBytes(tempValueS[0]);
                            }
                            break;
                        case 2:
                            {
                                var lastLength = temp.Description.ByteLength;
                                var startAddress = temp.Description.StartAddress;
                                Modbus.UnitIdentifier = temp.Description.UnitIdentifier;

                                var tempValueS = Modbus.ReadDiscreteInputs(startAddress, 1);//线圈就读一个


                                temp.Description.NewReceivedBytes = BitConverter.GetBytes(tempValueS[0]);
                            }
                            break;
                        case 3:
                            {
                                var lastLength = temp.Description.ByteLength;
                                var startAddress = temp.Description.StartAddress;
                                Modbus.UnitIdentifier = temp.Description.UnitIdentifier;

                                temp_In_tempData = Modbus.ReadHoldingRegisters(startAddress, lastLength / 2);//数据读取字节数除以2


                            }
                            break;
                        case 4:
                            {
                                var lastLength = temp.Description.ByteLength;
                                var startAddress = temp.Description.StartAddress;
                                Modbus.UnitIdentifier = temp.Description.UnitIdentifier;

                                temp_In_tempData = Modbus.ReadInputRegisters(startAddress, lastLength / 2);//数据读取字节数除以2


                            }
                            break;
                        default:
                            break;
                    }

                    if (temp.Functioncode != 1 && temp.Functioncode != 2)
                    {
                        //数据转换
                        temp.Description.NewReceivedBytes = Tools.DataValuesConvert2Bytes.Int16S_To_ByteS(temp_In_tempData);
                    }

                    temp.Description.LastReceivedBytes = temp.Description.NewReceivedBytes;
                    temp.Description.LastReceivedDateTime = temp.Description.NewReceivedDateTime;
                    temp.Description.NewReceivedDateTime = DateTime.Now;

                    ReBackData?.Invoke(temp);
                    #endregion

                    result = "正常";
                }
                catch (Exception ex)
                {
                    //读取数据时出现错误。
                    
                    if (IsRun) 
                    {
                        Stop();
                        PushReadData(temp); //出现异常了，这个数据没读到，重新加到队列中去。
                    }
                    else
                    {

                    }
                    result = ex.Message;//读数据时出现异常，一般情况是超时，是Modbus从站那边出现了问题。
                }
                
            }
            else 
            {
                //此处需要补充一个重连机制
                result = "重连";
            }

            return result;
        }

        #endregion

    }
}
